module Util

    def debug(*args)
	puts "DEBUG: #{args.join(' ')}" if args
    end

    def exception(e)
        err = "[#{e.class}]\n"
        err << "MESSAGE: #{e}\n>>      " 
        err << e.backtrace.join("\n>>        ")
        err << "\n[/#{e.class}]\n" 
	$stderr.puts "#{err}\n"
        err
    end

    def error(*str)
        $stderr.puts "#{str.join(' ')}" if str && !str.empty?
        $stderr.puts unless str || str.empty?
    end

    def require_version(version, exact = false)
        major, minor, tiny = %w(MAJOR MINOR TEENY).map{|t| ::Config::CONFIG[t].to_i}
        rmajor, rminor, rtiny = "#{version}".split(/\./).map { |rev| rev.to_i }

        required = "#{rmajor}.#{rminor}.#{rtiny}"
        current = "#{major}.#{minor}.#{tiny}"

        exact_match = !exact || current == required
        major_match = major >= rmajor
        minor_match = !rminor || minor >= rminor
        tiny_match  = !rtiny || tiny >= rtiny

        unless exact_match && major_match && minor_match && tiny_match
          name = "#{_scriptname}(#{_scriptfile(false)})"
          measure = exact ? 'exactly' : 'greater than'
          error "#{name} requires ruby version #{measure} '#{required}'"
          error "but this you are currently using version '#{current}'"
          error
          exit 100
        end
    end
 
    def _scriptfile(run_name = true)
	run_name ? $0 : __FILE__
    end

    def _scriptname
	File::basename(_scriptfile)
    end

    def b(&block)
       block 
    end

    module_function :require_version
    module_function :_scriptfile
    module_function :_scriptname
    module_function :error
    module_function :exception
    module_function :debug
    module_function :b

    def self::resolve_path(path)
	path = File::expand_path("#{path}")
	begin
	    Pathname.new(path).realpath.to_s
	rescue Errno::ENOENT, Errno::ENOTDIR
	    path
	end
    end

    def self::hash_merge(*hashes)
	hashes.inject( Hash.new ) { |memo, hash| memo.update(hash) }
    end

    def self::pid?(id)
	begin
	    Process::kill 0, "#{id}".to_i 
	    true
	rescue Errno::ESRCH
	    false
        end
    end

    def self::nuke!(pid, suspend = 4, *signals)
        signals = %w(SIGTERM SIGQUIT SIGKILL) if !signals || signals.empty?
        pid = "#{pid}".to_i
        existed = false
        signals.each { |sig|
	    begin
                Process::kill(sig, pid)
                existed = true 
            rescue Errno::ESRCH
                break if existed 
            end
	    break unless alive?(pid)
            sleep suspend
            break unless alive?(pid)
        }
        return !alive?(pid)
    end

    def self::hostname
	@__hostname__ ||= Socket::gethostname
    end

    def self::uniq_filename(dir, name=self::_scriptname, ext="uniq")
        iq = -1
        ext = ".#{ext}" unless ext[0] == ?.
        path = "#{dir}/#{name}#{ext}" 
	path = "#{dir}/#{name}_#{iq += 1}#{ext}" while File.exist?(path)
        path
    end

    module Aliases
        def bind_rule(rule, sub = nil)
            @rules ||= Hash.new
            @rules[rule] = sub
        end

        def bind_alias(pattern, value = nil)
            @aliases ||= Hash.new
            @aliases[pattern] = value
        end

        def resolve(key)
            return nil unless key
            key = "#{key}".downcase
            @rules.each { |rule, sub|
                key.gsub!(rule, sub)
            } if @rules
            return key unless @aliases
            unmapped = nil
            @aliases.each { |pattern, value|
                m = pattern.match(key)
                unmapped = value || m[1] if m
                break if unmapped
            }
            return unmapped || key
        end
    end

    module Collections
	class FileArray < Array
	    def load_list(io)
		io.each_line { |line|
		    line.sub!(/#.*/,'').strip!
		    next if line.empty?
		    self << line 	
		}
	    end

	    def initialize(file)
		return load_list(file) if IO === file 
		open(file.respond_to?('path') ? file.path : "#{file}") { |f| 
		    load_list(f) }
	    end
	end 

	class HashList < Hash

	    attr_accessor :order

	    class << self
		def [](*args)
		    hsh = HashList.new
		    hsh.replace(args.shift) if Hash === args.first
		    hsh[args.shift] = args.shift until args.size.zero?
		    hsh
		end
	    end

	    def initialize(*args, &b)
	      super
	      @order = Array.new
	    end

	    alias _store store    
	    def store(key, value)
		@order.push(key) unless has_key?(key)
		super key, value
	    end
	    alias []= store

	    def == other
		return false if @order != other.order
		super other
	    end

	    def clear
		@order = Array.new
		super
	    end

	    def delete key
		@order.delete(key)
		super
	    end

	    def each_key
		@order.each { |k| yield(k) }
		self
	    end

	    def each_value
		@order.each { |k| yield(self[k]) }
		self
	    end

	    def each
		@order.each { |k| yield(k, self[k]) }
		self
	    end
	    alias each_pair each    

	    def delete_if
		@order.clone.each { |k| 
		    delete(k) if yield
		}
		self
	    end

	    def values
		e = []
		@order.each { |k| e.push self[k] }
		e
	    end

	    def keys 
		@order 
	    end

	    def invert
		other = Hash.new    
		@order.each { |k| other[self[k]] = k }
		other
	    end

	    def reject(&block) self.dup.delete_if(&block); end

	    def reject!(&block)
		other = reject(&block)
		self == other ? nil : other
	    end

	    def replace other
		@order = other.keys 
		super other
	    end

	    def shift
		key = @order.first
		key ? [key, delete(key)] : super
	    end

	    def unshift(k, v)
		unless self.include?(k)
		    @order.unshift(k)
		    _store(k,v)
		    return true
		end
		false
	    end

	    def push(k, v)
		unless self.include?(k)
		    @order.push(k)
		    _store(k, v)
		    return true
		end
		false
	    end

	    def pop
		key = @order.last
		key ? [key, delete(key)] : nil
	    end

	    def to_a
		ary = []
		each { |k, v| ary << [k, v] }
		ary
	    end

	    def to_s 
                self.to_a.to_s
            end

	    def inspect
		ary = []
		each {|k,v| ary << k.inspect + "=>" + v.inspect}
		'{' + ary.join(", ") + '}'
	    end

	    def update(other)
		other.each { |k,v| self[k] = v }
		self
	    end
	    alias :merge! update

	    def merge(other) self.dup(update(other)); end

	    def select
		ary = []
		each { |k,v| ary << [k,v] if yield(k, v) }
		ary
	    end

	    def class 
                Hash
            end
	end

        class Multi < HashList
            def initialize
		super { |h, k| h[k] = Array.new; h[k]; }
            end
        end
    end

    module Dynamic
	def method_missing(name, *args, &block)
	    m = "#{name}"[/\w*/]
	    Util::debug "Create dynamic attribute:", m

	    instance_eval <<-EOF
		def attr_#{m}(*val)
		    val = nil if val.empty?
		    val = val.first val.length == 1
		    @#{m} = val if val
		    @#{m}
		end

		alias_method #{m} attr_#{m}
		alias_method #{m}= attr_#{m}
		alias_method #{m}? attr_#{m}
		alias_method #{m}! attr_#{m}
	    EOF

	    send(name, *args)
	end
    end


    module Meta
	def wrap(name, &block)
	    alias_method("_#{name}".to_sym, "#{name}".to_sym)
	    define_method(:"#{name}_block") {block}

	    module_eval <<-EOF
		def #{name}(*_args, &_block)
		    m = method(:"_#{name}") if respond_to?(:"_#{name}")
		    #{name}_block.call(m, _args, _block, self)
		end
	    EOF
	end

	def module_wrap(method, &block)
	    meta.module_eval {
	      wrap(method) { |original, _args, _block, obj|
		block.call(original, _args, _block, obj)
	      }
	    }
	end


	def define(name, &block)
	    self.class.module_eval { 
		define_method(name, proc { |*args| block.call(*args) }) 
	    }
	end

	def meta
	    class << self; self; end
	end

	def meta_def(name, &block)
	    meta.instance_eval { 
		define_method(name, proc { |*args| block.call(*args) }) 
	    }
	end
    end
end
